import mqtt from 'mqtt';
import _ from 'lodash';
import { mqttUrl } from '../../../config/urlConfig';
import moment from 'moment';

class MqttCentre {
  constructor() {
    this.client = null;
    this.isFistConnect = false;
    this.timer = null;
    this.events = new Map();
    this.reEvents = new Map();
    this.topicData = {};
  }
}

MqttCentre.prototype.clearTimer = function () {
  this.timer && clearInterval(this.timer);
};

/**
 * 建立mqtt链接
 * 根据不同的环境进行链接建立
 * @param username  用户名
 * @param password  密码
 */
MqttCentre.prototype.connect = function (
  username = 'mosquitto',
  password = 'Mosquitto.com',
  url = mqttUrl,
  otherOpts = {},
) {
  this.end();
  this.client = mqtt.connect(url, {
    username: username,
    password: password,
    clientId: `${Math.random().toString(16).substr(2, 7)}${moment().valueOf()}`,
    clean: false,
    ...otherOpts,
  });
  this.client.on('connect', () => {
    // eslint-disable-next-line no-console
    console.log('connect');
    if (!this.isFistConnect) {
      this.isFistConnect = true;
      // 接收信息
      this.client?.on('message', (topic, message) => {
        this.clientMessage(topic, message);
      });
    } else {
      this.reEvents.forEach((callback, m) => {
        callback && callback(m);
      });
    }
  });
  const that = this;
  this.timer = setInterval(() => {
    if (!that.client.connected) {
      // eslint-disable-next-line no-console
      console.log('链接断了');
    }
  }, 1000 * 5);
  this.client.on('error', (error) => {
    // eslint-disable-next-line no-console
    console.log(error);
  });
};
function Uint8ArrayToString(fileData) {
  let dataString = '';
  for (let i = 0; i < fileData.length; i++) {
    dataString += String.fromCharCode(fileData[i]);
  }
  return dataString;
}
MqttCentre.prototype.clientMessage = function (topic, data) {
  try {
    let msg = data.length > 2000 ? Uint8ArrayToString(data) : String.fromCharCode.apply(null, data);
    let res = JSON.parse(decodeURIComponent(escape(msg)));
    this.events.forEach((value, key) => {
      let tArr = _.isArray(value.topic) ? value.topic : [value.topic];
      if (value.topic.includes('#') && topic.includes(value.topicWildcard)) {
        value.func && value.func(res, key, _.last(topic?.split('/') ?? []) ?? '');
      } else if (tArr.includes(topic)) {
        value.func && value.func(res, key, _.last(topic?.split('/') ?? []) ?? '');
      }
    });
  } catch (e) {
    // eslint-disable-next-line no-console
    console.log(e);
  }
};
/**
 * 添加重连机制的订阅方法
 * @param keyVal 唯一值
 * @param callback  回调函数
 */
MqttCentre.prototype.subscribeReconnect = function (keyVal = '', callback) {
  if (!this.client && !this.reEvents.has(keyVal)) return;
  this.reEvents.set(keyVal, callback);
};

MqttCentre.prototype.unsubscribeReconnect = function (keyVal = '') {
  if (!this.client) return;
  this.reEvents.delete(keyVal);
};

/**
 * 销毁方法 关闭链接
 */
MqttCentre.prototype.end = function () {
  this.client && this.client.end();
  this.client = null;
  this.reEvents.clear();
  this.isFistConnect = false;
  this.clearTimer();
  this.topicData = {};
  this.events.clear();
};

/**
 * 订阅
 */
MqttCentre.prototype.subscribe = function (
  messageType = '',
  topic = '',
  callback,
  topicWildcard = '',
) {
  if (!this.client) return;
  if (this.topicData[topic] === undefined) {
    this.client?.subscribe(topic);
    this.topicData[topic] = 1;
  } else {
    this.topicData[topic] = 1 + this.topicData[topic];
  }
  this.events.set(messageType, { topic: topic, func: callback, topicWildcard: topicWildcard });
};
MqttCentre.prototype.unsubscribe = function (messageType = '') {
  if (!this.client) return;
  const obj = this.events.get(messageType);
  if (obj) {
    let number = this.topicData[obj.topic];
    if (number - 1 === 0) {
      this.client.unsubscribe(obj.topic);
      this.topicData = _.omit(this.topicData, [`${obj.topic}`]);
    } else {
      this.topicData[obj.topic] = number - 1;
    }
    this.events.delete(messageType);
  }
};
MqttCentre.getInstance = (function () {
  let instance;
  return function () {
    instance = instance ? instance : new MqttCentre();
    return instance;
  };
})();

export const mqttCentre = MqttCentre.getInstance();
